package org.az.netty_study.p07_netty组件之future和promise;

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * 上一章认识了ChannelFuture这个类，其中ChannelFuture继承了Future(netty)
 * Promise -> Future(netty) -> Future(jdk)
 *  1.Future(jdk):jdk提供的Future，可以获取线程的返回结果，只能同步等待任务结束后才能取得结果
 *  2.Future(netty):netty提供的Future，继承了Future(jdk)，可以以同步方式获取任务结果，也可以以异步方式，但都要等待任务执行结束
 *  3.Promise:继承了Future(netty)，不但有Future(netty)的全部功能，还可以脱离任务存在，作为两个线程间传递结果的容器
 */
@Slf4j
public class _2_future和promise {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 1.演示Future(jdk)
         */
        ExecutorService service = Executors.newSingleThreadExecutor();
        Future<String> jdkFuture = service.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("Future(jdk)子线程开始执行...");
                Thread.sleep(2000);
                log.info("Future(jdk)子线程执行成功...");
                return "执行成功";
            }
        });
        //通过Future获取子线程的执行结果,下面代码会一直阻塞，直到子线程执行结束并返回结果
        //Future(jdk)想要获取任务结果，只能同步阻塞，苦苦等待
        log.info("等待Future(jdk)结果");
        log.info("Future(jdk)子线程执行结果是:{}", jdkFuture.get());
        service.shutdown();

        /**
         * 2.演示Future(netty)
         */
        EventLoop eventLoop = new NioEventLoopGroup().next();
        io.netty.util.concurrent.Future<String> nettyFuture = eventLoop.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("Future(netty)子线程开始执行...");
                Thread.sleep(2000);
                log.info("Future(netty)子线程执行成功...");
                return "执行成功";
            }
        });
        //Future(netty)继承了Future(jdk)，当然可以使用Future(jdk)的方法
        //不过Future(netty)可以以异步方式得到任务执行结果，上一章用的就是这个方法
        //任务执行结束后，就会回调这个方法
        nettyFuture.addListener((GenericFutureListener) future -> {
            log.info("Future(jdk)子线程执行结果是:{}", future.getNow());
            //eventLoop.shutdownGracefully();
        });

        /**
         * 3.演示promise
         *   可以使用Promise，在任务执行过程中，主动将结果装进Promise
         */
        DefaultPromise<String> promise = new DefaultPromise<>(eventLoop);
        new Thread(() -> {
            log.info("promise开始计算");
            try {
                Thread.sleep(2000);
                log.info("promise计算完毕");
                int i = 1 / 0;
                //把计算结果填充进promise
                promise.setSuccess("promise执行成功");
            } catch (Exception e) {
                //计算失败
                promise.setFailure(e);
                //throw new RuntimeException(e);
            }
        }).start();

        //4.promise接收计算结果,Promise类继承了Future(netty),所以上面演示的方法,Promise都能用
        promise.addListener(future -> {
            eventLoop.shutdownGracefully();
            log.info("promise执行结果是:{}", promise.get());
        });
    }
}
